//
//  XMPPManager.m
//  RRT
//
//  Created by 涂操 on 15/2/10.
//  Copyright (c) 2015年 Asiainfo. All rights reserved.
//

#import "XMPPManager.h"

#import <CocoaLumberjack/DDTTYLogger.h>
#import <XMPPFramework/XMPPFramework.h>
#import <XMPPFramework/XMPPReconnect.h>
#import <XMPPFramework/XMPPAutoPing.h>


#define OPEN_DDLOG

#if DEBUG
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#else
static const int ddLogLevel = LOG_LEVEL_INFO;
#endif


@interface XMPPManager ()
{
    dispatch_queue_t msgReceQueue;
    NSTimer *reconnectTimer;
    int loginIMAuthenticateCount;
    GCDMulticastDelegate <XMPPManagerDelegate> *multicastDelegate;
}

@property (nonatomic, strong) XMPPStream *xmppStream;
@property (nonatomic, strong) XMPPReconnect *xmppReconnect;
@property (nonatomic, strong) XMPPAutoPing *xmppAutoPing;
@property (nonatomic, assign) BOOL isXmppConnected;
@property (nonatomic, strong) NSString *xLoginJid;
@property (nonatomic, strong) NSString *xPassword;
@property (nonatomic, assign) BOOL isLoginIMSuccess;
@property (nonatomic, copy) SuccessBlock successBlock;
@property (nonatomic, copy) FaildBlock faildBlock;

@end

@implementation XMPPManager


+ (instancetype)sharedInstance {
    static dispatch_once_t once;
    static XMPPManager *instance = nil;
    dispatch_once( &once, ^{ instance = [[XMPPManager alloc] init]; } );
    return instance;
}

- (id)init {
    self = [super init];
    if (self) {
        msgReceQueue = dispatch_queue_create("msgRecvQueue", NULL);
        multicastDelegate = (GCDMulticastDelegate <XMPPManagerDelegate> *)[[GCDMulticastDelegate alloc] init];
        [self setupStream];
        
#ifdef OPEN_DDLOG
        [DDLog addLogger:[DDTTYLogger sharedInstance]];
#endif
    }
    return self;
}

- (void)addDelegate:(id)delegate {
    [multicastDelegate addDelegate:delegate delegateQueue:NULL];
}

- (void)removeDelegate:(id)delegate {
    [multicastDelegate removeDelegate:delegate];
}


- (void)disconnectIMServer {
    _isXmppConnected = NO;
    //[self disconnectXmpp];
}

- (void)sendXMPPMessage:(XMPPMessage *)message {
    [_xmppStream sendElement:message];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)loginIMServerWithJID:(NSString *)myJid
                    password:(NSString *)myPwd
                     success:(SuccessBlock)success
                       error:(FaildBlock)faild {
    if (!myJid) {
        //myJid = @"student4";
        myJid = @"910000606@icloudedu.net/jsedu";
        myPwd = @"111111";
    }
    _xLoginJid = myJid;
    _xPassword = myPwd;
    _successBlock = success;
    _faildBlock = faild;
    [self connect];
}

- (void)setupXmppStreamWithHost:(NSString *)hostName port:(NSString *)hostPortStr {
    //test
    if (!hostName) {
        hostName = @"59.172.38.194";
        hostPortStr = @"25225";
    }

    [_xmppStream setHostName:hostName];
    [_xmppStream setHostPort:hostPortStr.intValue];
}

- (void)setupStream {
    if (!_xmppStream) {
        _xmppStream = [[XMPPStream alloc] init];
        [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }

#if !TARGET_IPHONE_SIMULATOR
    {
        _xmppStream.enableBackgroundingOnSocket = YES;
    }
#endif
    if (!_xmppReconnect) {
        _xmppReconnect = [[XMPPReconnect alloc] init];
        [_xmppReconnect activate:_xmppStream];
        _xmppReconnect.autoReconnect = YES;
    }
}

- (void)teardownStream {
    [_xmppStream removeDelegate:self];
    [_xmppReconnect deactivate];
    [_xmppStream disconnect];
    _xmppStream = nil;
    _xmppReconnect = nil;
}

- (void)goOnline {
    //XMPPPresence *presence = [XMPPPresence presence]; // type="available" is implicit
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
    [_xmppStream sendElement:presence];
}

- (void)goOffline {
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    [_xmppStream sendElement:presence];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Connect/disconnect
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (BOOL)connect {
    DDLogVerbose(@"链接开始～～～～～");
    if (![_xmppStream isDisconnected]) {
        return YES;
    }
    _isLoginIMSuccess = NO;
    
    if (_xLoginJid == nil || _xPassword == nil) {
        _faildBlock(nil,nil,LoginIMFial_NoJidOrPwd);
        return NO;
    }

    [_xmppStream setMyJID:[XMPPJID jidWithString:_xLoginJid]];
    
    NSError *error = nil;
    if (![_xmppStream connectWithTimeout:10 error:&error]) {
        DDLogError(@"Error connecting: %@", error);
        _faildBlock(nil,nil,LoginIMFial_ConnectError);
        return NO;
    }
    return YES;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPStream Delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}

- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    
    NSString *expectedCertName = [_xmppStream.myJID domain];
    if (expectedCertName) {
        [settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
    }
}

- (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    
    // The delegate method should likely have code similar to this,
    // but will presumably perform some extra security code stuff.
    // For example, allowing a specific self-signed certificate that is known to the app.
    
    dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(bgQueue, ^{
        
        SecTrustResultType result = kSecTrustResultDeny;
        OSStatus status = SecTrustEvaluate(trust, &result);
        
        if (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) {
            completionHandler(YES);
        }
        else {
            completionHandler(NO);
        }
    });
}

- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}

- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    NSError *error = nil;
    if (![_xmppStream authenticateWithPassword:_xPassword error:&error]) {
        DDLogError(@"Error authenticating: %@", error);
        _faildBlock(nil,nil,LoginIMFial_AuthenticateError);
    }
}

- (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    _isLoginIMSuccess = YES;
    [self goOnline];
    _successBlock(nil);
    [self setupXmppAutoPingWithJID:_xLoginJid];
}

- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    _faildBlock(nil,nil,LoginIMFial_AuthenticateFail);
}

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    return NO;
}

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)xMessage {
    DDLogVerbose(@"%@: %@,\n%@", THIS_FILE, THIS_METHOD,xMessage);
}

- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
    DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, presence);
}

- (void)xmppStream:(XMPPStream *)sender didReceiveError:(NSXMLElement *)error {
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}

- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {
    DDLogVerbose(@"%@: %@,%@", THIS_FILE, THIS_METHOD,error.localizedDescription);
}

#pragma mark -
#pragma mark XMPPReconnectDelegate
- (void)xmppReconnect:(XMPPReconnect *)sender didDetectAccidentalDisconnect:(SCNetworkReachabilityFlags)reachabilityFlags {
    //重新连接
}

- (BOOL)xmppReconnect:(XMPPReconnect *)sender shouldAttemptAutoReconnect:(SCNetworkReachabilityFlags)reachabilityFlags {
    return YES;
}

/**
 *  设置自动ping功能
 *
 *  @param JID 当前登录的jid
 */

- (void)setupXmppAutoPingWithJID:(NSString *)JID {
    if (!_xmppAutoPing) {
        _xmppAutoPing = [[XMPPAutoPing alloc] init];
        [_xmppAutoPing activate:_xmppStream];
        [_xmppAutoPing addDelegate:self delegateQueue:dispatch_get_main_queue()];
        _xmppAutoPing.respondsToQueries = YES;
        _xmppAutoPing.pingInterval=110;//ping 间隔时间
        _xmppAutoPing.pingTimeout = 10;
    }
    _xmppAutoPing.targetJID = [XMPPJID jidWithString:JID];//设置ping目标服务器，如果为nil,则监听socketstream当前连接上的那个服务器
}

#pragma mark -
#pragma mark xmppautoping delegate
- (void)xmppAutoPingDidSendPing:(XMPPAutoPing *)sender {
    
}

- (void)xmppAutoPingDidReceivePong:(XMPPAutoPing *)sender {
    //pingTimeoutCounts = 0;
}

- (void)xmppAutoPingDidTimeout:(XMPPAutoPing *)sender {
//    if (pingTimeoutCounts > 15 && pingTimeoutCounts%3==0 ) {
//        [self reconnectServerByTimer];
//    }
//    pingTimeoutCounts ++;
}



- (void)dealloc {
    [self teardownStream];
}

@end
